﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Diagnostics;
using Engine.Dtd.Schema;
using Engine.Sgml.Validation;
using Engine.Sgml.Matching;

namespace Engine.Sgml {
    /// <summary>
    /// This stack maintains a high water mark for allocated objects so the client
    /// can reuse the objects in the stack to reduce memory allocations, this is
    /// used to maintain current state of the parser for element stack, and attributes
    /// in each element.
    /// </summary>
    [DebuggerNonUserCode]
    class SObjectCollection<TElement> : HwStack<TElement> where TElement : SObject {
        public SObjectCollection(int capacity, Func<TElement> generator)
            : base(capacity, generator) {
            }

        public bool Contains(string name) {
            for (int i = 0; i < Count; i++)
                if (items[i].Equals(name))
                    return true;
            return false;
            }

        public bool Contains(TElement item) {
            for (int i = 0; i < Count; i++)
                if (ElementMatcher.Match(items[i], item))
                    return true;
            return false;
            }

        public TElement this[string name] {
            get {
                SName sname;
                if (SName.TryGet(name, out sname))
                    for (int i = 0; i < Count; i++) {
                        if (items[i].Name == sname)
                            return items[i];
                        }
                return default(TElement);
                }
            }

        internal TElement this[DName name] {
            get {
                for (int i = 0; i < Count; i++)
                    if (name == items[i].DName)
                        return items[i];
                return null;
                }
            }

        protected override void OnInsertElement(TElement element, int index) {
            items[index] = element;
            element.OrderIndex = index;
            }

        protected override void OnMoveElement(TElement element, int index) {
            items[index] = element;
            element.OrderIndex = index;
            }

        protected override void OnRemoveElement(TElement element, int index) {
            items[index] = default(TElement);
            element.OrderIndex = -1;
            }

        internal TElement FindAfter(int position, TElement element) {
            for (int i = position + 1; i < Count; i++)
                if (ElementMatcher.Match(items[i], element))
                    return items[i];
            return null;
            }

        internal TElement FindAfter(int position, DName name) {
            for (int i = position + 1; i < Count; i++)
                if (name == items[i].DName)
                    return items[i];
            return null;
            }

        internal TElement FindBefore(int position, TElement element) {
            for (int i = 0; i < position; i++)
                if (ElementMatcher.Match(items[i], element))
                    return items[i];
            return null;
            }

        internal bool ContainsAfter(int position, TElement element) {
            for (int i = position + 1; i < Count; i++)
                if (ElementMatcher.Match(items[i], element))
                    return true;
            return false;
            }

        internal bool ContainsBefore(int position, TElement element) {
            for (int i = 0; i < position; i++)
                if (ElementMatcher.Match(items[i], element))
                    return true;
            return false;
            }

        internal bool ContainsBefore(int position, int start, TElement element) {
            for (int i = start; i < position; i++)
                if (ElementMatcher.Match(items[i], element))
                    return true;
            return false;
            }

        internal bool Exists(int position, DName name) {
            if (position < Count)
                return items[position].DName == name;
            else
                return false;
            }

        internal bool Exists(int position, SgmlNodeType type) {
            if (position < Count)
                return items[position].NodeType == type;
            else
                return false;
            }

        internal bool Exists(int position, TElement element) {
            if (position < Count)
                return ElementMatcher.Match(items[position], element);
            else
                return false;
            }
        }
    }
